package com.jyh.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jyh.blog.dao.MenuDao;
import com.jyh.blog.dao.RoleMenuDao;
import com.jyh.blog.dto.LabelOptionDTO;
import com.jyh.blog.dto.MenuDTO;
import com.jyh.blog.dto.UserMenuDTO;
import com.jyh.blog.entity.Menu;
import com.jyh.blog.entity.RoleMenu;
import com.jyh.blog.exception.MyException;
import com.jyh.blog.service.MenuService;
import com.jyh.blog.utils.BeanCopyUtils;
import com.jyh.blog.utils.UserUtils;
import com.jyh.blog.vo.ConditionVO;
import com.jyh.blog.vo.MenuHiddenVO;
import com.jyh.blog.vo.MenuVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.jyh.blog.constant.CommonConst.COMPONENT;
import static com.jyh.blog.constant.CommonConst.TRUE;

/**
 * (Menu)表服务实现类
 *
 * @author jyh
 * @since 2023-02-15 11:40:37
 */
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuDao, Menu> implements MenuService {
    @Autowired
    private RoleMenuDao roleMenuDao;
    @Autowired
    private MenuDao menuDao;

    @Override
    public List<MenuDTO> menuList(ConditionVO conditionVO) {
        String keywords = conditionVO.getKeywords();
        //查询菜单数据
        List<Menu> menuList = this.list(new LambdaQueryWrapper<Menu>().like(StringUtils.isNotBlank(keywords), Menu::getName, keywords));
        //查询目录
        List<Menu> catalogList = catalogList(menuList);
        //查询目录下的子菜单
        Map<Integer, List<Menu>> childrenMenu = childrenMenu(menuList);
        //封装目录和子菜单
        List<MenuDTO> menuDTOList = BeanCopyUtils.copyList(catalogList, MenuDTO.class).stream().map(item -> {
            List<MenuDTO> childList = BeanCopyUtils.copyList(childrenMenu.get(item.getId()), MenuDTO.class).stream()
                    .sorted(Comparator.comparing(MenuDTO::getOrderNum))
                    .collect(Collectors.toList());
            item.setChildren(childList);
            childrenMenu.remove(item.getId());
            return item;
        }).collect(Collectors.toList());
        //还有子菜单出去拼接
        if (CollectionUtils.isNotEmpty(childrenMenu)) {
            List<Menu> childList = new ArrayList<>();
            childrenMenu.values().forEach(childList::addAll);
            List<MenuDTO> childMenu = childList.stream().map(item -> BeanCopyUtils.copyObject(item, MenuDTO.class))
                    .sorted(Comparator.comparing(MenuDTO::getOrderNum))
                    .collect(Collectors.toList());
            menuDTOList.addAll(childMenu);
        }

        return menuDTOList;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveOrUpdateMenu(MenuVO menuVO) {
        Menu menu = BeanCopyUtils.copyObject(menuVO, Menu.class);
        this.saveOrUpdate(menu);
    }

    @Override
    public void deleteMenuById(Integer menuId) {
        if (ObjectUtils.isNull(menuId)) {
            throw new MyException("菜单id不能为空");
        }
        //有角色关联的菜单不能删
        int count = roleMenuDao.selectCount(new LambdaQueryWrapper<RoleMenu>()
                .eq(RoleMenu::getMenuId, menuId));
        if (count > 0) {
            throw new MyException("角色正在使用菜单，不能删除");
        }
        //查询menuId的子菜单
        List<Integer> idList = this.list(new LambdaQueryWrapper<Menu>()
                .eq(Menu::getParentId, menuId))
                .stream().map(Menu::getId).collect(Collectors.toList());
        idList.add(menuId);
        this.removeByIds(idList);
    }

    @Override
    public void changHidden(MenuHiddenVO menuHiddenVO) {
        Menu menu = BeanCopyUtils.copyObject(menuHiddenVO, Menu.class);
        this.updateById(menu);
    }

    @Override
    public List<LabelOptionDTO> roleMenuList() {
        //查询菜单数据
        List<Menu> menuList = this.list(new LambdaQueryWrapper<Menu>()
                .select(Menu::getId, Menu::getName, Menu::getParentId,Menu::getOrderNum));
        //查询目录
        List<Menu> catalogList = catalogList(menuList);
        //查询目录下的子菜单
        Map<Integer, List<Menu>> childrenMenu = childrenMenu(menuList);
        //封装目录和子菜单
        //遍历父目录
        return catalogList.stream().map(item -> {
            List<LabelOptionDTO> list = new ArrayList<>();
            //根据父id获取子目录列表
            List<Menu> child = childrenMenu.get(item.getId());
            //构建子目录
            if (CollectionUtils.isNotEmpty(child)) {
                list = child.stream()
                        .sorted(Comparator.comparing(Menu::getOrderNum))
                        .map(menu -> LabelOptionDTO.builder()
                                .id(menu.getId())
                                .label(menu.getName())
                                .build()).collect(Collectors.toList());
            }
            return LabelOptionDTO.builder()
                    .id(item.getId())
                    .label(item.getName())
                    .children(list)
                    .build();
        }).collect(Collectors.toList());
    }

    @Override
    public List<UserMenuDTO> userMenuList() {
        //根据当前用户查询对应角色的菜单
        List<Menu> userMenuList= menuDao.userMenuByUserId(UserUtils.getLoginUser().getUserInfoId());
        userMenuList.remove(null);
        if(CollectionUtils.isEmpty(userMenuList)){
            throw new MyException("该用户不能登录，请联系管理员");
        }
        //父菜单
        List<Menu> catalogList = catalogList(userMenuList);
        //子菜单
        Map<Integer, List<Menu>> childrenMap = childrenMenu(userMenuList);
        //生成用户菜单

        return convertUserMenuList(catalogList,childrenMap);
    }

    private List<UserMenuDTO> convertUserMenuList(List<Menu> catalogList, Map<Integer, List<Menu>> childrenMap) {
        return catalogList.stream().map(item -> {
            // 获取目录
            UserMenuDTO userMenuDTO = new UserMenuDTO();
            List<UserMenuDTO> list = new ArrayList<>();
            // 获取目录下的子菜单
            List<Menu> children = childrenMap.get(item.getId());
            if (CollectionUtils.isNotEmpty(children)) {
                // 多级菜单处理
                userMenuDTO = BeanCopyUtils.copyObject(item, UserMenuDTO.class);
                list = children.stream()
                        .sorted(Comparator.comparing(Menu::getOrderNum))
                        .map(menu -> {
                            UserMenuDTO dto = BeanCopyUtils.copyObject(menu, UserMenuDTO.class);
                            dto.setHidden(menu.getIsHidden().equals(TRUE));
                            return dto;
                        })
                        .collect(Collectors.toList());
            } else {
                // 一级菜单处理
                userMenuDTO.setPath(item.getPath());
                userMenuDTO.setComponent(COMPONENT);
                list.add(UserMenuDTO.builder()
                        .path("")
                        .name(item.getName())
                        .icon(item.getIcon())
                        .component(item.getComponent())
                        .build());
            }
            userMenuDTO.setHidden(item.getIsHidden().equals(TRUE));
            userMenuDTO.setChildren(list);
            return userMenuDTO;
        }).collect(Collectors.toList());
    }

    /**
     * 目录菜单
     *
     * @param menus
     * @return
     */
    private List<Menu> catalogList(List<Menu> menus) {
        //过滤出父id为空，以Order_num排序
        return menus.stream()
                .filter(item -> ObjectUtils.isNull(item.getParentId()))
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .collect(Collectors.toList());
    }

    /**
     * 子菜单，key为父id
     *
     * @param menus
     * @return
     */
    private Map<Integer, List<Menu>> childrenMenu(List<Menu> menus) {
        //过滤出父id不为空，按父id分组
        return menus.stream()
                .filter(item -> ObjectUtils.isNotNull(item.getParentId()))
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .collect(Collectors.groupingBy(Menu::getParentId));
    }

}

